iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Vue.js

遊戲活動關卡查詢網站系列 第 21

遊戲活動關卡查詢網站Day21-條件查詢1(Vue:v-model)

  • 分享至 

  • xImage
  •  

目標
這個段落分兩篇講述 大部分是先前鐵人文章已經講過的作法
我們一樣用草稿規劃到資料整理方式匯出至Supabase
並呈現在畫面上
最後會提到我們下一篇需要整理出的資料 用作查詢使用

步驟
1.
因為當初線稿及資料沒規劃到這一塊
所以現在來補做

線稿如下圖 我們這次要做的是D組件和R組件
按下條件查詢時 只會顯示D和R組件

簡易版Schema和資料規劃如下圖
接著把CSV檔案匯至Supabase

上述資料的架構設計 參考當初線稿的畫面2.1
列出條件查詢需要篩選的項目

我們拿前兩筆資料的資料來看
行動方式和敵人屬性 如下圖
為了呈現這個畫面 資料結構需要轉換一下

我們需要將剛才匯入Supabase的資料

[
  {
    "id": 1,
    "name": "行動方式",
    "coditionType": "行動方式",
    "eleType": "0",
    "order": 1,
    "memo": ""
  },
  {
    "id": 2,
    "name": "先制",
    "coditionType": "行動方式",
    "eleType": "3",
    "order": 1,
    "memo": ""
  },
  {
    "id": 3,
    "name": "一般",
    "coditionType": "行動方式",
    "eleType": "3",
    "order": 1,
    "memo": ""
  },
  {
    "id": 4,
    "name": "憤怒",
    "coditionType": "行動方式",
    "eleType": "3",
    "order": 1,
    "memo": ""
  },
  {
    "id": 5,
    "name": "死亡",
    "coditionType": "行動方式",
    "eleType": "3",
    "order": 1,
    "memo": ""
  },
  {
    "id": 6,
    "name": "敵人屬性",
    "coditionType": "敵人屬性",
    "eleType": "0",
    "order": 2,
    "memo": ""
  },
  {
    "id": 7,
    "name": "水",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  },
  {
    "id": 8,
    "name": "火",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  },
  {
    "id": 9,
    "name": "雷",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  },
  {
    "id": 10,
    "name": "光",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  },
  {
    "id": 11,
    "name": "暗",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  },
  {
    "id": 12,
    "name": "無",
    "coditionType": "敵人屬性",
    "eleType": "3",
    "order": 2,
    "memo": ""
  }
]

整理成以下架構
先以coditionType分組
再以eleType分組

[
  {
    "coditionType": "行動方式",
    "info": [
      { "eleType": "0", "name": ["行動方式"] },
      { "eleType": "3", "name": ["先制","一般", "憤怒", "死亡"] }
    ]
  },
  {
    "coditionType": "敵人屬性",
    "info": [
      { "eleType": "0", "name": ["敵人屬性"] },
      { "eleType": "3", "name": ["水","火", "雷", "光", "暗", "無"] }
    ]
  }
]

將D組件的script增加為以下程式架構
而searchList是我們將Supabase取資料後轉換的結果

<script setup>
import { supabase } from "../supabase.js";
import { ref, onMounted,computed } from "vue";
const result = ref([]);
const searchResult = ref([]);
const searchCondition = ref(
  [
  { checked: false, name: "" ,coditionType:"行動方式",value:"1"},
  { checked: false, name: "" ,coditionType:"敵人屬性",value:"2"},
  { checked: false, name: "" ,coditionType:"種族",value:"3"},
  { checked: false, name: "" ,coditionType:"標記",value:"4"},
  { checked: false, name: "" ,coditionType:"負面狀態",value:"5"},
  { checked: false, name: "" ,coditionType:"詛咒",value:"5"},
  { checked: false, name: "" ,coditionType:"其他行動",value:"5"},
  { checked: false, name: "" ,coditionType:"關卡效果",value:"6"},
  { checked: false, name: "" ,coditionType:"憤怒條件",value:"7"},
  { checked: false, name: "" ,coditionType:"攻擊方式",value:"5"}
  ]
);


onMounted(async () => {
  const { data, error } = await supabase
    .from("skillSearch")
	.select("*");

  if (error) {
    console.error(error);
  } else {
    result.value = data;
  }
});
const searchList = computed(() => {
	const sorted = [...result.value].sort((a, b) => a.order - b.order);

	const grouped = {};
	sorted.forEach(item => {
	if (!grouped[item.coditionType]) {
	grouped[item.coditionType] = {};
	}
	
	if (!grouped[item.coditionType][item.eleType]) {
	grouped[item.coditionType][item.eleType] = [];
	}
	grouped[item.coditionType][item.eleType].push(item.name);
	});

	return Object.keys(grouped).map(type => {
	const info = Object.keys(grouped[type]).map(ele => ({
	eleType: ele,
	name: grouped[type][ele]
	}));
	return { coditionType: type, info };
	});
})
</script>

template程式架構如下

<template>
<div style="overflow:auto">
<div class="row" v-for="(item,index) in searchList" :key="item.coditionType">
	<div class="col-6">
		<div class="form-check">
			<input class="form-check-input" type="checkbox" v-model="searchCondition[index].checked" :id="'title'+index">
			<label class="form-check-label" :for="'title'+index">
			{{item.info[0].name[0]}}
			</label>
		</div>
	</div>
	<div class="col-6">
		<div class="row">
				<div class="col-6" v-for="(child,index2) in item.info[1].name" :key="index2">
					<div class="form-check">
					<input class="form-check-input" type="radio" :value="child" :name="item.coditionType" 
					:id=" item.coditionType + index2" v-model="searchCondition[index].name">
					<label class="form-check-label" :for="item.coditionType + index2">
					{{child}}
					</label>
				</div>
			</div>
			</div>
		</div>
</div>
</div>
</template>

下圖是目前呈現的畫面

因為我們預期的效果是
當前面有勾選且後面的值也有選時 才會進入查詢條件
所以我們用了v-model去綁定searchCondition
來方便管理我們查詢條件的狀態
到這一步,D組件的畫面已經幾乎完成,剩下取資料給R組件
我們留到下一篇繼續敘述

備註
這一篇其實有跳過一些父組件和子組件的架構
由於前面的篇數已經提過 這篇主要著重資料的處理;
另外使用searchCondition這個屬性去管理除了方便外
主要是為了下一篇取Supabase資料做準備

這邊講一下searchCondition這個屬性的架構
可以看到searchCondition 初始的定義是這樣

如下圖 當我們在畫面上勾選行動方式、敵人屬性
且後面也有選值時

searchCondition屬性則會變化如下圖紅框處


上一篇
遊戲活動關卡查詢網站Day20-我的最愛3(Vue:Module)
下一篇
遊戲活動關卡查詢網站Day22-條件查詢2(Supabase:PostgreSQL)
系列文
遊戲活動關卡查詢網站23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言